{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e9f9752c",
   "metadata": {},
   "source": [
    "加载题目列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a18fac46",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "question list size is 90, simple question is:\n",
      "id='smp25_pre_001' question='A Report on the Current State and Challenges of Explainable AI (XAI) Technology' type='Cutting-Edge Tech & AI' word_limit=1091\n"
     ]
    }
   ],
   "source": [
    "from tools import load_question\n",
    "\n",
    "question_list = load_question('preliminary_data/preliminary.json')\n",
    "print(f'question list size is {len(question_list)}, simple question is:\\n{question_list[0]}')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47f31d72",
   "metadata": {},
   "source": [
    "加载模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a72b680",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\86173\\AppData\\Local\\Temp\\ipykernel_21048\\3242308239.py:5: LangChainDeprecationWarning: The class `ChatOpenAI` was deprecated in LangChain 0.0.10 and will be removed in 1.0. An updated version of the class exists in the :class:`~langchain-openai package and should be used instead. To use it run `pip install -U :class:`~langchain-openai` and import as `from :class:`~langchain_openai import ChatOpenAI``.\n",
      "  chatLLM = ChatOpenAI(\n"
     ]
    }
   ],
   "source": [
    "from tools import load_env\n",
    "from langchain_community.chat_models import ChatOpenAI\n",
    "\n",
    "env = load_env('env.toml')\n",
    "chatLLM = ChatOpenAI(\n",
    "    api_key=env.API_KEY,\n",
    "    # model='Qwen/Qwen3-8B',\n",
    "    model='qwen-plus',  # 阿里百炼模型\n",
    "    base_url=env.BASE_URL,\n",
    "    temperature=0.7,\n",
    "    max_tokens=5120\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4468b9a8",
   "metadata": {},
   "source": [
    "构建提示词模板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c0567a0b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "template = '''\n",
    "你是一位擅长从报告的逻辑深度、论证质量、观点洞察力及整体完成度考虑的报告生成专家。\n",
    "你的需要生成一篇主题是{type}题材的关于{question}的报告。要求：生成的报告字数必须严格控制在{word_limit}字左右\n",
    "'''\n",
    "prompt = PromptTemplate.from_template(template)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23a55184",
   "metadata": {},
   "source": [
    "生成并提取结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bc06314d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['question', 'type', 'word_limit'], input_types={}, partial_variables={}, template='\\n你是一位擅长从报告的逻辑深度、论证质量、观点洞察力及整体完成度考虑的报告生成专家。\\n你的需要生成一篇主题是{type}题材的关于{question}的报告。要求：生成的报告字数必须严格控制在{word_limit}字左右\\n')\n",
       "| ChatOpenAI(client=<openai.resources.chat.completions.completions.Completions object at 0x000001D3243FAEF0>, async_client=<openai.resources.chat.completions.completions.AsyncCompletions object at 0x000001D324429840>, model_name='qwen-plus', model_kwargs={}, openai_api_key='sk-c158bec309c24c83b331a7efe99394f9', openai_api_base='https://dashscope.aliyuncs.com/compatible-mode/v1', openai_proxy='', max_tokens=5120)\n",
       "| StrOutputParser()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.output_parsers import  StrOutputParser\n",
    "\n",
    "chain = prompt | chatLLM | StrOutputParser()\n",
    "chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f608c1b0",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "running:   0%|          | 0/90 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "running: 100%|██████████| 90/90 [02:02<00:00,  1.34s/it]"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'submission/preliminary_submission_20250824-143355.json'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import asyncio\n",
    "from tqdm import tqdm\n",
    "from itertools import zip_longest\n",
    "from datetime import  datetime\n",
    "from tools import question2answer, save_answer\n",
    "\n",
    "batch_size = 30\n",
    "\n",
    "def group_elements(n, iterable, padvalue=None):\n",
    "    return zip_longest(*[iter(iterable)] * n, fillvalue=padvalue)\n",
    "\n",
    "answer_list = []\n",
    "task_bar = tqdm(total=len(question_list), desc='running')\n",
    "\n",
    "for batch_list in group_elements(batch_size, question_list, None):\n",
    "    result_list = await asyncio.gather(*[\n",
    "        chain.ainvoke(question.model_dump())\n",
    "        for question in batch_list if question is not None\n",
    "    ])\n",
    "    \n",
    "    for idx in range(len(result_list)):\n",
    "        answer_str = result_list[idx]\n",
    "        question = batch_list[idx]\n",
    "        if not question:\n",
    "            continue\n",
    "        answer_list.append(question2answer(question, answer_str))\n",
    "    task_bar.update(len(batch_list))\n",
    "    \n",
    "save_path = f'submission/preliminary_submission_{datetime.now().strftime(\"%Y%m%d-%H%M%S\")}.json'\n",
    "save_answer(answer_list, save_path)\n",
    "save_path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ad38667c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "误差率：428.40 %\n"
     ]
    }
   ],
   "source": [
    "from tools import Answer\n",
    "\n",
    "rate_list = []\n",
    "for answer in answer_list:\n",
    "    obj: Answer = answer\n",
    "    dif_rate = abs(len(obj.answer) - obj.word_limit) / obj.word_limit\n",
    "    rate_list.append(dif_rate)\n",
    "    \n",
    "print('误差率：%.2f %%' % (sum(rate_list) / len(rate_list) * 100))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
